home *** CD-ROM | disk | FTP | other *** search
/ Acorn User: China / Acorn User China CD-ROM (UK) (Disc A) / Acorn User China CD-ROM (UK) (Disc A).bin / DEMON / MISC / NETLITE2.ARC / NET / c / DOMAIN < prev    next >
Encoding:
Text File  |  1993-04-13  |  14.0 KB  |  556 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include "werr.h"
  6. #include "dbox.h"
  7. #include "global.h"
  8. #include "cmdparse.h"
  9. #include "mbuf.h"
  10. #include "netuser.h"
  11. #include "udp.h"
  12. #include "internet.h"
  13. #include "timer.h"
  14. #include "domain.h"
  15. #include "ip.h"
  16. #include "misc.h"
  17.  
  18. #define Domain_OK      0
  19. #define Domain_Suffix  2
  20. #define Domain_Timeout 4
  21. #define Domain_Tries   6
  22.  
  23. int32 domain_servers[MAX_SERVERS];
  24. int domain_server_count = 0;
  25.  
  26. char *domain_suffix = NULLCHAR;
  27. int  domain_timeout = 10;
  28. int  domain_tries   = 2;
  29. int  domain_trace   = 0;
  30.  
  31. extern int16 lport;
  32. extern char  *badhost;
  33.  
  34. struct domain_stat domain_stat;
  35.  
  36. static int  doaddserver(int, char **);
  37. static int  dosuffix(int, char **);
  38. static int  dotimeout(int, char **);
  39. static int  dotries(int, char **);
  40. static void send_domain_request(struct domain_request *);
  41. static void recv_domain(struct socket *, int, void *);
  42. static void timeout_domain(void *);
  43. static int  tokenise_host(char *, char *);
  44. static int  detokenise_host(char *, char *, char *);
  45. static int32 interpret_a(struct domain_request *, char *, int);
  46. static int32 interpret_mx(struct domain_request *, char *, int);
  47.  
  48. struct cmds domcmds[] =
  49. {
  50.         "addserver",    doaddserver,    0,      NULLCHAR,       NULLCHAR,
  51.         "suffix",       dosuffix,       0,      NULLCHAR,       NULLCHAR,
  52.         "timeout",      dotimeout,      0,      NULLCHAR,       NULLCHAR,
  53.         "tries",        dotries,        0,      NULLCHAR,       NULLCHAR,
  54.         NULLCHAR,       NULLFP,         0,
  55.                 "domain subcommands: addserver suffix timeout tries",
  56.         NULLCHAR,
  57. };
  58.  
  59. int dodomain(int argc, char **argv)
  60. {
  61.         return subcmd(domcmds, argc, argv);
  62. }
  63.  
  64. static int doaddserver(int argc, char **argv)
  65. {
  66.         int32 n;
  67.  
  68.         if (argc > 1)
  69.         {
  70.                 if ((n = resolve(argv[1])) == 0)
  71.                 {
  72.                         werr(0, badhost, argv[1]);
  73.                         return(1);
  74.                 }
  75.  
  76.                 domain_servers[domain_server_count++] = n;
  77.         }
  78.  
  79.         return(0);
  80. }
  81.  
  82. static int dosuffix(int argc, char **argv)
  83. {
  84.         if (argc > 1)
  85.         {
  86.                 if (domain_suffix != NULLCHAR) free(domain_suffix);
  87.                 domain_suffix = strdup(argv[1]);
  88.         }
  89.  
  90.         return(0);
  91. }
  92.  
  93. static int dotimeout(int argc, char **argv)
  94. {
  95.         if (argc > 1) domain_timeout = atoi(argv[1]);
  96.         return 0;
  97. }
  98.  
  99. static int dotries(int argc, char **argv)
  100. {
  101.         if (argc > 1) domain_tries = atoi(argv[1]);
  102.         return 0;
  103. }
  104.  
  105. void domain_parms(void)
  106. {
  107.         char Suffix[81];
  108.         dbox d;
  109.  
  110.         if ((d = dbox_new("Dom_Parms")) == NULL)
  111.                 return;
  112.  
  113.         dbox_setfield(d,   Domain_Suffix,  domain_suffix);
  114.         dbox_setnumeric(d, Domain_Timeout, domain_timeout);
  115.         dbox_setnumeric(d, Domain_Tries,   domain_tries);
  116.  
  117.         dbox_show(d);
  118.  
  119.         if (dbox_fillin(d) == Domain_OK)
  120.         {
  121.                dbox_getfield(d, Domain_Suffix, Suffix, 80);
  122.                domain_timeout = dbox_getnumeric(d, Domain_Timeout);
  123.                domain_tries   = dbox_getnumeric(d, Domain_Tries);
  124.  
  125.                if (domain_suffix != NULLCHAR) free(domain_suffix);
  126.                domain_suffix = strdup(Suffix);
  127.         }
  128.  
  129.         dbox_dispose(&d);
  130. }
  131.  
  132. void resolve_a(char *host, char *arg1, char *arg2, void *user, int (*function)(), int (*error)())
  133. {
  134.         struct domain_request *request;
  135.         char *fullhost;
  136.         int32 n;
  137.  
  138.         if ((n = resolve(host)) != 0)
  139.         {
  140.                (*function)(n, host, arg1, arg2, user);
  141.                return;
  142.         }
  143.  
  144.         if (domain_server_count == 0)
  145.         {
  146.                (*error)(host, "no domain servers known", user);
  147.                return;
  148.         }
  149.  
  150.         if ((request = (struct domain_request *)malloc(sizeof(struct domain_request))) == NULLDOMREQ)
  151.         {
  152.                (*error)(host, "out of memory", user);
  153.                return;
  154.         }
  155.  
  156.         fullhost = malloc(256);
  157.  
  158.         strcpy(fullhost, host);
  159.  
  160.         if (strchr(host, '.') == NULL && domain_suffix != NULLCHAR)
  161.         {
  162.                strcat(fullhost, ".");
  163.                strcat(fullhost, domain_suffix);
  164.         }       
  165.  
  166.         if (fullhost[strlen(fullhost) - 1] != '.')
  167.                strcat(fullhost, ".");
  168.  
  169.         request->socket   = lport++;
  170.         request->id       = clock() & 0xFFFF;
  171.  
  172.         request->domain_t.func = timeout_domain;
  173.         request->domain_t.arg  = (void *)request;
  174.  
  175.         request->server   = 0;
  176.         request->tries    = 0;
  177.         request->type     = TYPE_A;
  178.         request->class    = CLASS_IN;
  179.         request->function = function;
  180.         request->error    = error;
  181.  
  182.         request->host     = fullhost;
  183.         request->user     = user;
  184.  
  185.         if (arg1 != NULLCHAR)
  186.                request->arg1 = strdup(arg1);
  187.         else
  188.                request->arg1 = NULLCHAR;
  189.  
  190.         if (arg2 != NULLCHAR)
  191.                request->arg2 = strdup(arg2);
  192.         else
  193.                request->arg2 = NULLCHAR;
  194.  
  195.         send_domain_request(request);
  196. }
  197.  
  198. void resolve_mx(char *host, void *user, int (*function)(), int (*error)())
  199. {
  200.         struct domain_request *request;
  201.  
  202.         if (domain_server_count == 0)
  203.         {
  204.                (*error)(host, "no domain servers known", user);
  205.                return;
  206.         }
  207.  
  208.         if ((request = (struct domain_request *)malloc(sizeof(struct domain_request))) == NULLDOMREQ)
  209.         {
  210.                (*error)(host, "out of memory", user);
  211.                return;
  212.         }
  213.  
  214.         if (host[strlen(host) - 1] != '.')
  215.                strcat(host, ".");
  216.  
  217.         request->socket   = lport++;
  218.         request->id       = clock() & 0xFFFF;
  219.  
  220.         request->domain_t.func = timeout_domain;
  221.         request->domain_t.arg  = (void *)request;
  222.  
  223.         request->server   = 0;
  224.         request->tries    = 0;
  225.         request->type     = TYPE_MX;
  226.         request->class    = CLASS_IN;
  227.         request->function = function;
  228.         request->error    = error;
  229.         request->host     = strdup(host);
  230.         request->user     = user;
  231.         request->arg1     = NULLCHAR;
  232.         request->arg2     = NULLCHAR;
  233.  
  234.         send_domain_request(request);
  235. }
  236.  
  237. static void send_domain_request(struct domain_request *request)
  238. {
  239.         struct socket fsock, lsock;
  240.         struct mbuf *bp;
  241.         int hostlen;
  242.  
  243.         domain_stat.packets_out[request->type]++;
  244.  
  245.         lsock.address = ip_addr;
  246.         lsock.port    = request->socket;
  247.  
  248.         fsock.address = domain_servers[request->server];
  249.         fsock.port    = DOMAIN_PORT;
  250.  
  251.         bp = alloc_mbuf(512);
  252.  
  253.         put16(bp->data + 0, request->id);
  254.         bp->data[2] = QR_QUERY | OPCODE_QUERY | RD;
  255.         bp->data[3] = 0x00;
  256.  
  257.         put16(bp->data + 4,  1);
  258.         put16(bp->data + 6,  0);
  259.         put16(bp->data + 8,  0);
  260.         put16(bp->data + 10, 0);
  261.  
  262.         hostlen = tokenise_host(request->host, bp->data + 12);
  263.  
  264.         put16(bp->data + hostlen + 12, request->type);
  265.         put16(bp->data + hostlen + 14, request->class);
  266.  
  267.         bp->cnt = hostlen + 16;
  268.  
  269.         send_udp(&lsock, &fsock, 0, 0, bp, 0, 0, 0);
  270.  
  271.         if (request->tries == 0)
  272.                open_udp(&lsock, recv_domain, request);
  273.  
  274.         set_timer(&request->domain_t, domain_timeout * (1000 / MSPTICK));
  275.  
  276.         start_timer(&request->domain_t);
  277. }
  278.  
  279. static void recv_domain(struct socket *socket, int recvcnt, void *arg)
  280. {
  281.         static char reply[512];        /* UDP maximum size */
  282.         struct domain_request *request;
  283.         struct socket fsock;
  284.         struct mbuf *bp;
  285.         int32  address;
  286.         int    size;
  287.  
  288.         recvcnt = recvcnt;
  289.         request = (struct domain_request *)arg;
  290.  
  291.         stop_timer(&request->domain_t);
  292.  
  293.         recv_udp(socket, &fsock, &bp);
  294.         size = dqdata(bp, reply, 512);
  295.  
  296.         if (request->id != get16(reply + 0))
  297.         {
  298.                 domain_stat.invalid_id++;
  299.                 werr(0, "bad id on received packet");
  300.                 return;
  301.         }
  302.  
  303.         domain_stat.packets_in[request->type]++;
  304.  
  305.         switch (request->type)
  306.         {
  307.                 case TYPE_A:
  308.                        address = interpret_a(request, reply, size);
  309.                        break;
  310.                 case TYPE_MX:
  311.                        address = interpret_mx(request, reply, size);
  312.                        break;
  313.                 default:
  314.                        break;
  315.         }
  316.  
  317.         del_udp(socket);
  318.  
  319.         if (address == 0)
  320.                 (*request->error)(request->host, "name not resolvable", request->user);
  321.         else
  322.                 (*request->function)(address, request->host, request->arg1, request->arg2, request->user);
  323.  
  324.         free(request->host);
  325.         if (request->arg1 != NULLCHAR) free(request->arg1);
  326.         if (request->arg2 != NULLCHAR) free(request->arg2);
  327.         free(request);
  328. }
  329.  
  330. static void timeout_domain(void *arg)
  331. {
  332.         struct domain_request *request;
  333.         struct socket socket;
  334.  
  335.         request = (struct domain_request *)arg;
  336.  
  337.         domain_stat.timeouts++;
  338.  
  339.         request->server++;
  340.  
  341.         if (request->server == domain_server_count)
  342.         {
  343.                 request->tries++;
  344.                 request->server = 0;
  345.  
  346.                 if (request->tries == domain_tries)
  347.                 {
  348.                        socket.address = ip_addr;
  349.                        socket.port    = request->socket;
  350.  
  351.                        del_udp(&socket);
  352.  
  353.                        (*request->error)(request->host, "no reply from name servers", request->user);
  354.  
  355.                        free(request->host);
  356.                        if (request->arg1 != NULLCHAR) free(request->arg1);
  357.                        if (request->arg2 != NULLCHAR) free(request->arg2);
  358.                        free(request);
  359.                        return;
  360.                 }
  361.         }
  362.  
  363.         send_domain_request(request);
  364. }
  365.  
  366. static int32 interpret_a(struct domain_request *request, char *s, int n)
  367. {
  368.         static char hosta[256];
  369.         static char hostb[256];
  370.         int16 rdlength;
  371.         int16 qdcount;
  372.         int16 ancount;
  373.         int16 type;
  374.         char *t;
  375.         int i;
  376.  
  377.         n = n;
  378.  
  379.         qdcount = get16(s + 4);
  380.         ancount = get16(s + 6);
  381.  
  382.         if (qdcount != 1) return(0);
  383.         if (ancount == 0) return(0);
  384.  
  385.         strcpy(hosta, request->host);
  386.  
  387.         /* Skip QNAME, QTYPE and QCLASS */
  388.         for (t = s + 0x0C; *t != 0x00 && *t != 0xC0; t++);
  389.         if (*t == 0xC0) t++;
  390.         t += 5;
  391.  
  392.         for (i = 0; i < ancount; i++)
  393.         {
  394.                detokenise_host(t, hostb, s);
  395.  
  396.                for (; *t != 0x00 && *t != 0xC0; t++);
  397.                if (*t == 0xC0) t++;
  398.                t++;
  399.  
  400.                type     = get16(t + 0);
  401.                rdlength = get16(t + 8);
  402.  
  403.                if (strcmp(hosta, hostb) == 0)
  404.                {
  405.                        if (type == TYPE_A)
  406.                                return(get32(t + 10));
  407.  
  408.                        if (type == TYPE_CNAME)
  409.                                detokenise_host(t + 10, hosta, s);
  410.                }
  411.  
  412.                t += rdlength + 10;
  413.         }
  414.  
  415.         return(0);
  416. }
  417.  
  418. static int32 interpret_mx(struct domain_request *request, char *s, int n)
  419. {
  420.         static char hosta[256];
  421.         static char hostb[256];
  422.         int16 rdlength;
  423.         int16 preference;
  424.         int16 qdcount;
  425.         int16 ancount;
  426.         int16 nscount;
  427.         int16 arcount;
  428.         int16 type;
  429.         char *t;
  430.         int i;
  431.  
  432.         n = n;
  433.  
  434.         qdcount = get16(s + 4);
  435.         ancount = get16(s + 6);
  436.         nscount = get16(s + 8);
  437.         arcount = get16(s + 10);
  438.         preference = 9999;
  439.  
  440.         if (qdcount != 1) return(0);
  441.         if (ancount == 0) return(0);
  442.  
  443.         strcpy(hosta, request->host);
  444.  
  445.         /* Skip QNAME, QTYPE and QCLASS */
  446.         for (t = s + 0x0C; *t != 0x00 && *t != 0xC0; t++);
  447.         if (*t == 0xC0) t++;
  448.         t += 5;
  449.  
  450.         for (i = 0; i < ancount; i++)
  451.         {
  452.                detokenise_host(t, hostb, s);
  453.  
  454.                for (; *t != 0x00 && *t != 0xC0; t++);
  455.                if (*t == 0xC0) t++;
  456.                t++;
  457.  
  458.                type     = get16(t + 0);
  459.                rdlength = get16(t + 8);
  460.  
  461.                if (strcmp(hosta, hostb) == 0 && type == TYPE_MX)
  462.                {
  463.                        if (get16(t + 10) < preference)
  464.                        {
  465.                                preference = get16(t + 10);
  466.                                detokenise_host(t + 12, hosta, s);
  467.                        }
  468.                }
  469.  
  470.                t += rdlength + 10;
  471.         }
  472.  
  473.         for (i = 0; i < nscount; i++)
  474.         {
  475.                for (; *t != 0x00 && *t != 0xC0; t++);
  476.                if (*t == 0xC0) t++;
  477.                t++;
  478.  
  479.                rdlength = get16(t + 8);
  480.  
  481.                t += rdlength + 10;
  482.         }
  483.  
  484.         for (i = 0; i < arcount; i++)
  485.         {
  486.                detokenise_host(t, hostb, s);
  487.  
  488.                for (; *t != 0x00 && *t != 0xC0; t++);
  489.                if (*t == 0xC0) t++;
  490.                t++;
  491.  
  492.                type     = get16(t + 0);
  493.                rdlength = get16(t + 8);
  494.  
  495.                if (strcmp(hosta, hostb) == 0 && type == TYPE_A)
  496.                        return(get32(t + 10));
  497.  
  498.                t += rdlength + 10;
  499.         }
  500.  
  501.         return(0);
  502. }
  503.  
  504. static int tokenise_host(char *host, char *buffer)
  505. {
  506.         char *h;
  507.         char *b;
  508.         char *s;
  509.  
  510.         h = strdup(host);
  511.         b = buffer;
  512.  
  513.         s = strtok(h, ".");
  514.  
  515.         while (s != NULLCHAR)
  516.         {
  517.                  *b++ = strlen(s);
  518.                  while (*s != '\0') *b++ = *s++;
  519.                  s = strtok(NULLCHAR, ".");
  520.         }
  521.  
  522.         *b++ = 0;
  523.  
  524.         free(h);
  525.  
  526.         return(b - buffer);
  527. }
  528.  
  529. static int detokenise_host(char *thost, char *ahost, char *reply)
  530. {
  531.         int16 pointer;
  532.         char *hostname;
  533.         int n;
  534.  
  535.         hostname = ahost;
  536.  
  537.         while (*thost != 0)
  538.         {
  539.                 if ((*thost & 0xC0) == 0xC0)
  540.                 {
  541.                         pointer = get16(thost) & 0x3FFF;
  542.                         thost = reply + pointer;
  543.                 }
  544.                 else
  545.                 {
  546.                         n = *thost++;
  547.                         while (n-- > 0) *hostname++ = *thost++;
  548.                         *hostname++ = '.';
  549.                 }
  550.         }
  551.  
  552.         *hostname++ = '\0';
  553.  
  554.         return(hostname - ahost);
  555. }
  556.